#define DOP_RELOAD_LDT (1<<1) /* Reload the LDT shadow mapping. */
unsigned long deferred_ops;
unsigned long cr0;
- /* General-Purpose Subject, Page-Table Subject */
- struct domain *gps, *pts;
+ /* If non-NULL, specifies a foreign subject domain for some operations. */
+ struct domain *foreign;
} percpu_info[NR_CPUS] __cacheline_aligned;
-/* Determine the current General-Purpose Subject or Page-Table Subject. */
-#define PTS (percpu_info[smp_processor_id()].pts ? : current)
-#define GPS (percpu_info[smp_processor_id()].gps ? : current)
-
+/*
+ * Returns the current foreign domain; defaults to the currently-executing
+ * domain if a foreign override hasn't been specified.
+ */
+#define FOREIGNDOM (percpu_info[smp_processor_id()].foreign ? : current)
void ptwr_init_backpointers(void);
* frame if it is mapped by a different L2 table. This is sufficient and
* also necessary to allow validation of an L2 table mapping itself.
*/
-static int get_linear_pagetable(l2_pgentry_t l2e, unsigned long pfn)
+static int
+get_linear_pagetable(
+ l2_pgentry_t l2e, unsigned long pfn, struct domain *d)
{
u32 x, y;
struct pfn_info *page;
if ( (l2_pgentry_val(l2e) >> PAGE_SHIFT) != pfn )
{
/* Make sure the mapped frame belongs to the correct domain. */
- if ( unlikely(!get_page_from_pagenr(l2_pgentry_to_pagenr(l2e), PTS)) )
+ if ( unlikely(!get_page_from_pagenr(l2_pgentry_to_pagenr(l2e), d)) )
return 0;
/*
}
-static int get_page_from_l1e(l1_pgentry_t l1e)
+static int
+get_page_from_l1e(
+ l1_pgentry_t l1e, struct domain *d)
{
unsigned long l1v = l1_pgentry_val(l1e);
unsigned long pfn = l1_pgentry_to_pagenr(l1e);
if ( l1v & _PAGE_RW )
{
if ( unlikely(!get_page_and_type_from_pagenr(
- pfn, PGT_writeable_page, GPS)) )
+ pfn, PGT_writeable_page, d)) )
return 0;
set_bit(_PGC_tlb_flush_on_type_change,
&frame_table[pfn].u.inuse.count_info);
return 1;
}
- return get_page_from_pagenr(pfn, GPS);
+ return get_page_from_pagenr(pfn, d);
}
/* NB. Virtual address 'l2e' maps to a machine address within frame 'pfn'. */
-static int get_page_from_l2e(l2_pgentry_t l2e, unsigned long pfn)
+static int
+get_page_from_l2e(
+ l2_pgentry_t l2e, unsigned long pfn, struct domain *d)
{
if ( !(l2_pgentry_val(l2e) & _PAGE_PRESENT) )
return 1;
}
if ( unlikely(!get_page_and_type_from_pagenr(
- l2_pgentry_to_pagenr(l2e), PGT_l1_page_table, PTS)) )
- return get_linear_pagetable(l2e, pfn);
+ l2_pgentry_to_pagenr(l2e), PGT_l1_page_table, d)) )
+ return get_linear_pagetable(l2e, pfn, d);
return 1;
}
static int alloc_l2_table(struct pfn_info *page)
{
- unsigned long page_nr = page - frame_table;
- l2_pgentry_t *pl2e;
- int i;
+ struct domain *d = page->u.inuse.domain;
+ unsigned long page_nr = page_to_pfn(page);
+ l2_pgentry_t *pl2e;
+ int i;
pl2e = map_domain_mem(page_nr << PAGE_SHIFT);
for ( i = 0; i < DOMAIN_ENTRIES_PER_L2_PAGETABLE; i++ ) {
- if ( unlikely(!get_page_from_l2e(pl2e[i], page_nr)) )
+ if ( unlikely(!get_page_from_l2e(pl2e[i], page_nr, d)) )
goto fail;
set_l1_page_va(l2_pgentry_val(pl2e[i]) >> PAGE_SHIFT, i);
}
static int alloc_l1_table(struct pfn_info *page)
{
- unsigned long page_nr = page - frame_table;
- l1_pgentry_t *pl1e;
- int i;
+ struct domain *d = page->u.inuse.domain;
+ unsigned long page_nr = page_to_pfn(page);
+ l1_pgentry_t *pl1e;
+ int i;
pl1e = map_domain_mem(page_nr << PAGE_SHIFT);
for ( i = 0; i < ENTRIES_PER_L1_PAGETABLE; i++ )
- if ( unlikely(!get_page_from_l1e(pl1e[i])) )
+ if ( unlikely(!get_page_from_l1e(pl1e[i], d)) )
goto fail;
unmap_domain_mem(pl1e);
if ( ((l2_pgentry_val(ol2e) ^ l2_pgentry_val(nl2e)) & ~0xffe) == 0 )
return update_l2e(pl2e, ol2e, nl2e);
- if ( unlikely(!get_page_from_l2e(nl2e, pfn)) )
+ if ( unlikely(!get_page_from_l2e(nl2e, pfn, current)) )
return 0;
set_l1_page_va(l2_pgentry_val(nl2e) >> PAGE_SHIFT,
if ( ((l1_pgentry_val(ol1e) ^ l1_pgentry_val(nl1e)) & ~0xffc) == 0 )
return update_l1e(pl1e, ol1e, nl1e);
- if ( unlikely(!get_page_from_l1e(nl1e)) )
+ if ( unlikely(!get_page_from_l1e(nl1e, FOREIGNDOM)) )
return 0;
if ( unlikely(!update_l1e(pl1e, ol1e, nl1e)) )
void free_page_type(struct pfn_info *page, unsigned int type)
{
+ struct domain *d = page->u.inuse.domain;
+
switch ( type )
{
case PGT_l1_page_table:
free_l1_table(page);
- if ( unlikely(current->mm.shadow_mode) &&
- (get_shadow_status(¤t->mm,
- page-frame_table) & PSH_shadowed) )
- {
- /*
- * Using 'current->mm' is safe and correct because page-table pages
- * are not shared across domains. Updates to such pages' types are
- * thus only done within the context of the owning domain. The one
- * exception is when destroying a domain; however, this is not a
- * problem as the currently-executing domain will not have this MFN
- * shadowed, and at domain end-of-day we explicitly unshadow
- * everything so that nothing will get left lying around.
- */
- unshadow_table( page-frame_table, type );
- put_shadow_status(¤t->mm);
- }
break;
case PGT_l2_page_table:
free_l2_table(page);
- if ( unlikely(current->mm.shadow_mode) &&
- (get_shadow_status(¤t->mm,
- page-frame_table) & PSH_shadowed) )
- {
- unshadow_table( page-frame_table, type );
- put_shadow_status(¤t->mm);
- }
break;
default:
BUG();
}
+
+ if ( unlikely(d->mm.shadow_mode) &&
+ (get_shadow_status(&d->mm, page_to_pfn(page)) & PSH_shadowed) )
+ {
+ unshadow_table(page_to_pfn(page), type);
+ put_shadow_status(&d->mm);
+ }
}
u32 x, y;
domid_t domid;
- cleanup_writable_pagetable(PTWR_CLEANUP_ACTIVE | PTWR_CLEANUP_INACTIVE);
-
switch ( cmd )
{
case MMUEXT_PIN_L1_TABLE:
okay = get_page_and_type_from_pagenr(
pfn,
(cmd==MMUEXT_PIN_L2_TABLE) ? PGT_l2_page_table : PGT_l1_page_table,
- PTS);
+ FOREIGNDOM);
if ( unlikely(!okay) )
{
MEM_LOG("Error while pinning pfn %08lx", pfn);
break;
case MMUEXT_UNPIN_TABLE:
- if ( unlikely(!(okay = get_page_from_pagenr(pfn, PTS))) )
+ if ( unlikely(!(okay = get_page_from_pagenr(pfn, FOREIGNDOM))) )
{
MEM_LOG("Page %08lx bad domain (dom=%p)",
ptr, page->u.inuse.domain);
break;
}
- case MMUEXT_SET_SUBJECTDOM:
- domid = ((domid_t)((ptr&~0xFFFF)|(val>>16)));
+ case MMUEXT_SET_FOREIGNDOM:
+ domid = (domid_t)(val >> 16);
if ( !IS_PRIV(d) )
{
}
else
{
- if ( percpu_info[cpu].gps != NULL )
- put_domain(percpu_info[cpu].gps);
- percpu_info[cpu].gps = find_domain_by_id(domid);
- percpu_info[cpu].pts = (val & SET_PAGETABLE_SUBJECTDOM) ?
- percpu_info[cpu].gps : NULL;
- if ( percpu_info[cpu].gps == NULL )
+ if ( (e = percpu_info[cpu].foreign) != NULL )
+ put_domain(e);
+
+ percpu_info[cpu].foreign = e = find_domain_by_id(domid);
+ if ( e == NULL )
{
MEM_LOG("Unknown domain '%u'", domid);
okay = 0;
break;
}
- if ( unlikely((e = percpu_info[cpu].gps) == NULL) )
+ e = percpu_info[cpu].foreign;
+ if ( unlikely(e == NULL) )
{
- MEM_LOG("No GPS to reassign pfn %08lx to", pfn);
+ MEM_LOG("No FOREIGNDOM to reassign pfn %08lx to", pfn);
okay = 0;
break;
}
spin_unlock(&e->page_alloc_lock);
break;
- case MMUEXT_RESET_SUBJECTDOM:
- if ( percpu_info[cpu].gps != NULL )
- put_domain(percpu_info[cpu].gps);
- percpu_info[cpu].gps = percpu_info[cpu].pts = NULL;
+ case MMUEXT_CLEAR_FOREIGNDOM:
+ if ( (e = percpu_info[cpu].foreign) != NULL )
+ put_domain(e);
+ percpu_info[cpu].foreign = NULL;
break;
default:
* MMU_NORMAL_PT_UPDATE: Normal update to any level of page table.
*/
case MMU_NORMAL_PT_UPDATE:
- if ( unlikely(!get_page_from_pagenr(pfn, PTS)) )
+ if ( unlikely(!get_page_from_pagenr(pfn, current)) )
{
MEM_LOG("Could not get page for normal update");
break;
break;
case MMU_MACHPHYS_UPDATE:
- if ( unlikely(!get_page_from_pagenr(pfn, GPS)) )
+ if ( unlikely(!get_page_from_pagenr(pfn, FOREIGNDOM)) )
{
MEM_LOG("Could not get page for mach->phys update");
break;
if ( deferred_ops & DOP_RELOAD_LDT )
(void)map_ldt_shadow_page(0);
- if ( unlikely(percpu_info[cpu].gps != NULL) )
+ if ( unlikely(percpu_info[cpu].foreign != NULL) )
{
- put_domain(percpu_info[cpu].gps);
- percpu_info[cpu].gps = percpu_info[cpu].pts = NULL;
+ put_domain(percpu_info[cpu].foreign);
+ percpu_info[cpu].foreign = NULL;
}
if ( unlikely(success_count != NULL) )
cleanup_writable_pagetable(PTWR_CLEANUP_ACTIVE | PTWR_CLEANUP_INACTIVE);
- percpu_info[cpu].gps = d = find_domain_by_id(domid);
+ percpu_info[cpu].foreign = d = find_domain_by_id(domid);
if ( unlikely(d == NULL) )
{
MEM_LOG("Unknown domain '%u'", domid);
rc = do_update_va_mapping(page_nr, val, flags);
put_domain(d);
- percpu_info[cpu].gps = NULL;
+ percpu_info[cpu].foreign = NULL;
return rc;
}
}
if (unlikely(l1_pgentry_val(ol1e) & _PAGE_PRESENT))
put_page_from_l1e(ol1e);
- if (unlikely(!get_page_from_l1e(nl1e)))
+ if (unlikely(!get_page_from_l1e(nl1e, current)))
BUG();
}
unmap_domain_mem(pl1e);
continue;
if (unlikely(l1_pgentry_val(ol1e) & _PAGE_PRESENT))
put_page_from_l1e(ol1e);
- if (unlikely(!get_page_from_l1e(nl1e)))
+ if (unlikely(!get_page_from_l1e(nl1e, current)))
BUG();
}
unmap_domain_mem(pl1e);
* HYPERVISOR_mmu_update() accepts a list of (ptr, val) pairs.
* ptr[1:0] specifies the appropriate MMU_* command.
*
- * GPS (General-Purpose Subject)
- * -----------------------------
- * This domain that must own all non-page-table pages that are involved in
- * MMU updates. By default it is the domain that executes mmu_update(). If the
- * caller has sufficient privilege then it can be changed by executing
- * MMUEXT_SET_SUBJECTDOM.
- *
- * PTS (Page-Table Subject)
- * ------------------------
- * This domain must own all the page-table pages that are subject to MMU
- * updates. By default it is the domain that executes mmu_update(). If the
- * caller has sufficient privilege then it can be changed by executing
- * MMUEXT_SET_SUBJECTDOM with val[14] (SET_PAGETABLE_SUBJECTDOM) set.
+ * FOREIGN DOMAIN (FD)
+ * -------------------
+ * Some commands recognise an explicitly-declared foreign domain,
+ * in which case they will operate with respect to the foreigner rather than
+ * the calling domain. Where the FD has some effect, it is described below.
*
* ptr[1:0] == MMU_NORMAL_PT_UPDATE:
- * Updates an entry in a page table.
- * ptr[:2] -- machine address of the page-table entry to modify [1]
- * val -- value to write [2]
+ * Updates an entry in a page table. If updating an L1 table, and the new
+ * table entry is valid/present, the mapped frame must belong to the FD, if
+ * an FD has been specified. If attempting to map an I/O page, then the FD
+ * is ignored, but the calling domain must have sufficient privilege.
+ * ptr[:2] -- Machine address of the page-table entry to modify.
+ * val -- Value to write.
*
* ptr[1:0] == MMU_MACHPHYS_UPDATE:
* Updates an entry in the machine->pseudo-physical mapping table.
- * ptr[:2] -- machine address within the frame whose mapping to modify [3]
- * val -- value to write into the mapping entry
+ * ptr[:2] -- Machine address within the frame whose mapping to modify.
+ * The frame must belong to the FD, if one is specified.
+ * val -- Value to write into the mapping entry.
*
* ptr[1:0] == MMU_EXTENDED_COMMAND:
- * val[7:0] -- MMUEXT_* command
+ * val[7:0] -- MMUEXT_* command.
*
* val[7:0] == MMUEXT_(UN)PIN_*_TABLE:
- * ptr[:2] -- machine address of frame to be (un)pinned as a p.t. page [1]
+ * ptr[:2] -- Machine address of frame to be (un)pinned as a p.t. page.
+ * The frame must belong to the FD, if one is specified.
*
* val[7:0] == MMUEXT_NEW_BASEPTR:
- * ptr[:2] -- machine address of new page-table base to install in MMU [1]
+ * ptr[:2] -- Machine address of new page-table base to install in MMU.
*
* val[7:0] == MMUEXT_TLB_FLUSH:
- * no additional arguments
+ * No additional arguments.
*
* val[7:0] == MMUEXT_INVLPG:
- * ptr[:2] -- linear address to be flushed from the TLB
+ * ptr[:2] -- Linear address to be flushed from the TLB.
*
* val[7:0] == MMUEXT_SET_LDT:
- * ptr[:2] -- linear address of LDT base (NB. must be page-aligned)
- * val[:8] -- number of entries in LDT
+ * ptr[:2] -- Linear address of LDT base (NB. must be page-aligned).
+ * val[:8] -- Number of entries in LDT.
*
- * val[7:0] == MMUEXT_SET_SUBJECTDOM:
- * val[14] -- if TRUE then sets the PTS in addition to the GPS.
- * (ptr[31:15],val[31:15]) -- dom[31:0]
+ * val[7:0] == MMUEXT_SET_FOREIGNDOM:
+ * val[31:15] -- Domain to set as the Foreign Domain (FD).
+ * (NB. DOMID_SELF is not recognised)
*
* val[7:0] == MMUEXT_REASSIGN_PAGE:
- * ptr[:2] -- machine address within page to be reassigned to the GPS.
- *
- * val[7:0] == MMUEXT_RESET_SUBJECTDOM:
- * Resets both the GPS and the PTS to their defaults (i.e., calling domain).
+ * ptr[:2] -- A machine address within the page to be reassigned to the FD.
+ * (NB. page must currently belong to the calling domain).
*
- * Notes on constraints on the above arguments:
- * [1] The page frame containing the machine address must belong to the PTS.
- * [2] If the PTE is valid (i.e., bit 0 is set) then the specified page frame
- * must belong to:
- * (a) the PTS (if the PTE is part of a non-L1 table); or
- * (b) the GPS (if the PTE is part of an L1 table).
- * [3] The page frame containing the machine address must belong to the GPS.
+ * val[7:0] == MMUEXT_CLEAR_FOREIGNDOM:
+ * Clears the FD.
*/
#define MMU_NORMAL_PT_UPDATE 0 /* checked '*ptr = val'. ptr is MA. */
#define MMU_MACHPHYS_UPDATE 2 /* ptr = MA of frame to modify entry for */
#define MMUEXT_TLB_FLUSH 6 /* ptr = NULL */
#define MMUEXT_INVLPG 7 /* ptr = VA to invalidate */
#define MMUEXT_SET_LDT 8 /* ptr = VA of table; val = # entries */
-#define MMUEXT_SET_SUBJECTDOM 9 /* (ptr[31:15],val[31:15]) = dom[31:0] */
-#define SET_PAGETABLE_SUBJECTDOM (1<<14) /* OR into 'val' arg of SUBJECTDOM */
+#define MMUEXT_SET_FOREIGNDOM 9 /* val[31:15] = dom */
#define MMUEXT_REASSIGN_PAGE 10
-#define MMUEXT_RESET_SUBJECTDOM 11
+#define MMUEXT_CLEAR_FOREIGNDOM 11
#define MMUEXT_CMD_MASK 255
#define MMUEXT_CMD_SHIFT 8
typedef u16 domid_t;
/* DOMID_SELF is used in certain contexts to refer to oneself. */
-#define DOMID_SELF (0x7FFEU)
+#define DOMID_SELF (0x7FF0U)
+/* NB. IDs >= 0x7FF1 are reserved for future use. */
/*
* Send an array of these to HYPERVISOR_mmu_update().